﻿//#define USE_DUNGEONBUDDY_DLL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Media;
using Bots.DungeonBuddy.Behaviors;
using CommonBehaviors.Actions;
using MainDev.RemoteASM.Handlers;
using Styx;
using Styx.Common.Helpers;
using Styx.CommonBot;
using Styx.CommonBot.Frames;
using Styx.Helpers;
using Styx.Patchables;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals.World;
using Action = Styx.TreeSharp.Action;
#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;

namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Mists_of_Pandaria
#else
    using Bots.DungeonBuddy.Profiles;
    using Bots.DungeonBuddy.Attributes;
    using Bots.DungeonBuddy.Helpers;
namespace Bots.DungeonBuddy.Dungeon_Scripts.Mists_of_Pandaria
#endif
{
    internal class ForgottenDepths : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 611; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(7278.526, 5002.926, 76.17107); } //verified by erenion
        }

        public override void OnEnter()
        {
            if (Me.IsTank())
            {
                Alert.Show(
                    "Tanking Not Supported",
                    string.Format(
                        "Tanking is not supported in the {0} script. If you wish to stay in raid and play manually then press 'Continue'. Otherwise you will automatically leave raid.",
                        Name),
                    30,
                    true,
                    true,
                    null,
                    () => Lua.DoString("LeaveParty()"),
                    "Continue",
                    "Leave");
            }
            else
            {
                Alert.Show(
                    "Do Not AFK",
                    "It is highly recommended you do not afk while in a raid and be prepared to intervene if needed in the event something goes wrong or you're asked to perform a certain task.",
                    20,
                    true,
                    false,
                    null,
                    null,
                    "Ok");
            }
        }

        public override void OnExit()
        {
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                o =>
                {
                    var unit = o as WoWUnit;
                    if (unit == null) return false;
                    if (unit.Entry == WhirlTurleID && unit.HasAura("Shell Block"))
                        return true;
                    return false;
                });
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit == null) continue;
                if (unit.Entry == WhirlTurleID && Me.IsMelee())
                    priority.Score -= 10000;
            }
        }


        readonly WoWPoint FlamingHeadLoc = new WoWPoint(6457.674, 4470.42, -209.6087);
        readonly WoWPoint VenomousHeadLoc = new WoWPoint(6401.996, 4518.628, -209.1766);

        readonly WoWPoint FlamingHeadMovetoLoc = new WoWPoint(6457.674, 4470.42, -209.6087);
        readonly WoWPoint VenomousHeadMovetoLoc = new WoWPoint(6373.982, 4521.059, -209.1758);

        public override MoveResult MoveTo(WoWPoint location)
        {
            if (location.DistanceSqr(FlamingHeadLoc) < 5 * 5)
                return Navigator.MoveTo(FlamingHeadMovetoLoc);
            if (location.DistanceSqr(VenomousHeadLoc) < 5 * 5)
                return Navigator.MoveTo(VenomousHeadMovetoLoc);
            return MoveResult.Failed;
        }

        #endregion

        private const uint GastropodId = 68220;


        private static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        [EncounterHandler(0)]
        public Composite RootEncounter()
        {
            AddAvoidObject(ctx => true, 10, u => u.Entry == GastropodId && ((WoWUnit)u).IsAlive && !u.ToUnit().Combat);
            // avoid trash...
            AddAvoidObject(
                ctx => true,
                o => o.ToUnit().MyAggroRange + 3,
                o => o is WoWUnit && ((WoWUnit)o).Attackable && ((WoWUnit)o).CanSelect && ((WoWUnit)o).IsHostile &&
                    !((WoWUnit)o).Combat && o.Distance <= 60 && !((WoWUnit)o).IsTargetingMyRaidMember && o.ZDiff < 20);

            return
                new PrioritySelector(
                    new Decorator(ctx => Me.Location.Distance(new WoWPoint()) < 5, ScriptHelpers.CreateJumpDown(ctx => !Me.Combat, new WoWPoint(), new WoWPoint())));
        }

        #region Tortos

        private const uint RockfallID = 68219;
        private const uint WhirlTurleID = 67966;

        [EncounterHandler(69712, "Tortos", Mode = CallBehaviorMode.Proximity)]
        public Composite TortosEncounter()
        {
            AddAvoidObject(ctx => true, 10, u => u.Entry == WhirlTurleID && ((WoWUnit)u).HasAura("Spinning Shell"));
            AddAvoidObject(ctx => true, 5, RockfallID);

            WoWUnit boss = null;
            AddAvoidObject(ctx => true, 7, FeedPoolId);
            // stay away from the spray target.
            return new PrioritySelector();
        }

        #endregion

        #region Madera

        private const uint CindersId = 70432;
        private readonly WoWPoint _cindersRunLocation = new WoWPoint(6332.51, 4802.359, -172.213);

        [LocationHandler(6435.174, 4546.373, -209.2975, 50, "Megaera")]
        public Composite MegaeraEncounter()
        {
            WaitTimer updateRaidLocTimer = new WaitTimer(TimeSpan.FromSeconds(2));
            AddAvoidObject(ctx => true, 7, CindersId);
            WoWPoint raidLocation = WoWPoint.Zero;
            WoWUnit boss = null;
            // stay away from the spray target.
            return new PrioritySelector(
                ctx =>
                {
                    if (updateRaidLocTimer.IsFinished)
                    {
                        raidLocation = ScriptHelpers.GetGroupCenterLocation(null, 20);
                        updateRaidLocTimer.Reset();
                    }
                    return boss = Targeting.Instance.FirstUnit;
                },
                new Decorator(ctx => Me.Debuffs.ContainsKey("Cinders"), new Action(ctx => Navigator.PlayerMover.MoveTowards(_cindersRunLocation))),
                // stack up on raid location.
                new Decorator(
                    ctx =>
                    {
                        if (boss == null || !Me.Combat) return false;
                        var raidDist = Me.Location.Distance(raidLocation);
                        var maxDpsRange = Me.IsMelee() ? boss.MeleeRange() : 36 + boss.CombatReach;
                        return raidLocation.Distance(boss.Location) <= maxDpsRange && raidDist > 10;
                    },
                    new Action(ctx => Navigator.MoveTo(raidLocation))));
        }

        #endregion

        #region Ji-Kun

        private const uint FeedPoolId = 68188;
        private const uint DownDraft = 134370; //pushes you off the edge
        private const uint DemonicGatewayId = 59262;
        private const uint JiKunId = 69712;

        [EncounterHandler(69712, "Ji-Kun", Mode = CallBehaviorMode.Proximity)]
        public Composite JiKunEncounter()
        {
            WoWUnit boss = null;
            WoWUnit feedPool = null;
            // stay away from the spray target.
            AddAvoidObject(ctx => Me.HealthPercent < 60, 7, FeedPoolId);
            AddAvoidObject(ctx => true, 23, u => u.Entry == JiKunId && !u.ToUnit().Combat && u.ToUnit().IsAlive && u.Distance <= 50);

            return new PrioritySelector(
                ctx =>
                {
                    // only have ranged dps move to the pools to aborb them.
                    feedPool = Me.HealthPercent >= 60 && Me.IsRangeDps()
                                   ? ObjectManager.GetObjectsOfType<WoWUnit>().Where(u => u.Entry == FeedPoolId).OrderBy(u => u.DistanceSqr).FirstOrDefault()
                                   : null;
                    return boss = ctx as WoWUnit;
                },
                new Decorator(
                    ctx => boss.CastingSpellId == DownDraft && (boss.Distance > 15 || Me.IsMelee() && !boss.IsWithinMeleeRange),
                    new Action(
                        ctx =>
                        {
                            var gateway = (WoWUnit)ObjectManager.ObjectList.Where(o => o.Entry == DemonicGatewayId && o.Location.Distance2D(boss.Location) > 20)
                                .OrderBy(u => u.Distance2DSqr)
                                .FirstOrDefault();
                            if (gateway != null && gateway.Distance < gateway.InteractRange)
                                gateway.Interact();
                            else
                                Navigator.PlayerMover.MoveTowards(boss.Location);
                        })),
                new Decorator(ctx => feedPool != null && feedPool.Distance > 4, new Action(ctx => Navigator.MoveTo(feedPool.Location))));
        }

        #endregion
    }
}